<template>
  <div class="CommonForm">
    <el-form ref="CommonFormRef" :model="modelValues" :rules="rules" :label-width="newProps.labelWidth" :size="newProps.size">
      <template v-for="item in newProps.formItems" :key="item.prop">
        <el-form-item :label-width="item.labelWidth" :label="item.label" :prop="item.prop">
          <!-- input框 -->
          <template v-if="item.type === 'input'">
            <el-input
              v-if="!item.inputType"
              v-model="modelValues[item.prop]"
              v-bind="item.attrs"
              :style="item.style"
              :placeholder="item.placeholder"
              :clearable="item.clearable"
              :size="item.size || newProps.size"
              :maxlength="config.inputMaxlength"
            ></el-input>
            <el-input
              v-else-if="item.inputType === 'number'"
              v-model.number="modelValues[item.prop]"
              v-bind="item.attrs"
              :style="item.style"
              :placeholder="item.placeholder"
              :clearable="item.clearable"
              :size="item.size || newProps.size"
              :maxlength="config.inputNumberMax"
            ></el-input>
          </template>
          <!-- 多行文本框 -->
          <el-input
            v-if="item.type === 'textarea'"
            v-model="modelValues[item.prop]"
            v-bind="item.attrs"
            type="textarea"
            :resize="item.resize || 'none'"
            :disabled="item.disabled"
            :maxlength="config.textareaMaxlength"
            show-word-limit
            :style="item.style"
            :autosize="{ minRows: !!item.minRows ? item.minRows : 2, maxRows: !!item.maxRows ? item.maxRows : 4 }"
            :placeholder="item.placeholder"
            :size="item.size || newProps.size"
          ></el-input>
          <!-- 选择框 -->
          <template v-if="item.type === 'select'">
            <el-select
              v-model="modelValues[item.prop]"
              v-bind="item.attrs"
              :style="item.style"
              :placeholder="item.placeholder"
              :filterable="item.filterable"
              :clearable="item.clearable"
              :size="item.size || newProps.size"
            >
              <el-option v-for="item in item.options" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
          </template>
          <!-- 单选框组 -->
          <template v-if="item.type === 'radioGroup'">
            <el-radio-group v-model="modelValues[item.prop]" v-bind="item.attrs" :style="item.style" :size="item.size || newProps.size">
              <el-radio v-for="radio in item.options" :key="radio.value" :label="radio.value" :disabled="radio.disabled">{{ radio.label }}</el-radio>
            </el-radio-group>
          </template>
          <!-- 复选框 -->
          <template v-if="item.type === 'checkbox'">
            <el-checkbox-group v-model="modelValues[item.prop]">
              <el-checkbox v-for="ch in item.checkboxs" :label="ch.value" :key="ch.value">{{ ch.label }}</el-checkbox>
            </el-checkbox-group>
          </template>
          <!-- 级联选择 -->
          <template v-if="item.type === 'cascader'">
            <el-cascader
              v-model="modelValues[item.prop]"
              v-bind="item.attrs"
              :style="item.style"
              :placeholder="item.placeholder"
              :options="item.options"
              :props="{ checkStrictly: true, value: item.props.value, label: item.props.label }"
              :clearable="item.clearable"
              :size="item.size || newProps.size"
            ></el-cascader>
          </template>
          <!-- 日期选择 -->
          <template v-if="item.type === 'date'">
            <el-date-picker
              v-model="modelValues[item.prop]"
              v-bind="item.attrs"
              :style="item.style"
              :type="item.type"
              :placeholder="item.placeholder"
              :clearable="item.clearable"
              :format="item.format"
              :value-format="item.format"
              :size="item.size || newProps.size"
            ></el-date-picker>
          </template>

          <!-- 时间选择 -->
          <template v-if="item.type === 'datePicker'">
            <el-date-picker
              v-model="modelValues[item.prop]"
              v-bind="item.attrs"
              :style="item.style"
              :type="item.type"
              :start-placeholder="item['startPlaceholder']"
              :end-placeholder="item['endPlaceholder']"
              :placeholder="item.placeholder"
              :format="item.format"
              :value-format="item.valueFormat || item.format"
              :clearable="item.clearable"
              :size="item.size || newProps.size"
            />
          </template>
          <!-- 按钮选择 -->
          <template v-if="item.type === 'button'">
            <el-button v-bind="item.attrs" :disabled="item.disabled" @click="clickBtn(item)" :size="item.size || newProps.size">
              {{ !!item.placeholder ? item.placeholder : '' }}
            </el-button>
          </template>
          <template v-if="item.type === 'buttonBadge'">
            <el-badge :value="modelValues[item.prop].length">
              <el-button v-bind="item.attrs" :disabled="item.disabled" @click="clickBtn(item)" :size="item.size || newProps.size">
                {{ !!item.placeholder ? item.placeholder : '' }}
              </el-button>
            </el-badge>
          </template>
        </el-form-item>
      </template>
    </el-form>
  </div>
</template>

<script name="CommonForm" lang="ts" setup>
  import { computed, reactive, ref, watch, watchEffect } from 'vue'
  import { Utils } from '@/utils'
  import config from '@/settings'

  //表单内子组件
  interface FormItem {
    labelWidth?: string | number // FormItem 标签的宽度
    label: string // FormItem 标签的label
    type: string // 组件类型
    prop: string // 组件值的键值
    value?: any // 默认值
    attrs?: object // 组件属性
    style?: object // 组件样式
    placeholder?: string
    clearable?: boolean // 是否显示清空icon
    size?: string
    filterable: boolean // select 是否可搜索
    disabled?: boolean
    format?: any // datePicker 是否可搜索
    resize?: any // textarea  可否缩放
    maxLength?: string | number // textarea 最大字符
    minRows: string | number // textarea 最大Row
    maxRows: string | number // textarea 最小Row
    startPlaceholder: string // datePicker startPlaceholder
    endPlaceholder: string // datePicker  endPlaceholder
    options?: Array<any> // select 列表
    checkboxs: Array<any> // checkbox 列表
  }

  //传递属性
  interface Props {
    modelValue?: any
    labelWidth?: string | number //标签的宽度
    size?: string // 组件的尺寸
    disabled?: boolean // 禁用该表单内的所有组件
    formItems?: Array<FormItem | any>
    rules?: object
  }

  const emit = defineEmits<{
    (e: 'update:modelValue', data: any): void
    (e: 'clickBtn', data: any): void
  }>()

  const props = withDefaults(defineProps<Props>(), {
    modelValue: {},
    labelWidth: '120px',
    size: 'medium',
    formItems: () => [],
    rules: () => ({})
  })

  /**
   * 标题设置
   * label: string 标题
   * needType: boolean 是否需要冒号 defaultValue： true
   */
  const labelSet = (label: string, needType: boolean = true): string => {
    let flag = label.indexOf(':') > 0 || label.indexOf('：') > 0
    if (needType) {
      if (flag) {
        return label
      } else {
        return label + '：'
      }
    } else {
      if (flag) {
        return label.slice(0, label.length - 2)
      } else {
        return label
      }
    }
  }
  /**
   * placeholder 设置
   */
  const placeholderSet = (e: FormItem): string => {
    switch (e.type) {
      case 'input':
        return '请输入' + labelSet(e.label, false)
      case 'select':
        return '请选择' + labelSet(e.label, false)
      default:
        return '请选择' + labelSet(e.label, false)
    }
  }

  // props 默认值相关处理
  const resloveProps = (props: Props) => {
    const newProps: Props = Utils.deepClone(props)
    const modelValues: any = {}
    newProps.formItems?.forEach((item: FormItem) => {
      if ('clearable' in item) {
        item.clearable = item.clearable === undefined || !!item.clearable === true ? true : false
      }
      if ('filterable' in item) {
        item.filterable = !!item.filterable === true ? true : false
      }
      if ('disabled' in item) {
        item.disabled = !!item.disabled === true ? true : false
      }

      item.label = labelSet(item.label)

      item.placeholder = item.placeholder ? item.placeholder : placeholderSet(item)

      modelValues[item.prop] = item.value || ''
    })
    return { modelValues, newProps }
  }

  const CommonFormRef = ref<any>(null)
  const newProps = resloveProps(props).newProps

  const modelValues = computed({
    get: () => props.modelValue,
    set: () => emit('update:modelValue', resloveProps(props).modelValues)
  })

  //button
  const clickBtn = (item: FormItem) => {
    emit('clickBtn', item)
  }

  //当前值
  function getFormValue() {
    return Utils.deepClone(modelValues)
  }

  //表单验证
  function validate(callback: Function) {
    CommonFormRef.value.validate((valid: boolean) => callback && callback(valid))
  }

  //表单单个属性验证
  function validateField(props: Array<any> | string, callback?: (errorMessage: string) => any) {
    CommonFormRef.value.validateField(props, callback)
  }

  //表单重置
  function resetFields(callback: Function) {
    CommonFormRef.value.resetFields()
  }

  defineExpose({ getFormValue, validate, validateField, resetFields })
</script>

<style lang="scss" scoped>
  ::v-deep .el-form-item__label {
    padding: 0;
  }
  ::v-deep(.el-form-item) {
    .el-select {
      width: 100%;
    }
    &:last-child {
      .el-form-item__content {
        margin-left: 0 !important;
        .button-center {
          transform: translateX(-50%);
          margin-left: 50%;
          .el-button + .el-button {
            margin-left: 40px;
          }
        }
      }
    }
  }
</style>
